package wmsignerjx;

import java.io.UnsupportedEncodingException;
import java.util.Random;

public final class Signer {

	private static final int USHORT_BYTES = 2;
	private static final int VALUE_BYTES = 56;
	private static final int HASH_LEN = 16;
	private static final int INT_BYTES = 4;

	private final int[] exponent;
	private final int[] modulus;

	private final boolean randomize;
	private final Random rnd = new Random();


	public Signer(byte[] exponent, byte[] modulus, boolean randomize) {
		int[] intExpon = new int[(exponent.length - 1) / INT_BYTES + 1];
		int[] intModul = new int[(modulus.length - 1) / INT_BYTES + 1];

		Buffer.BlockCopy(exponent, 0, intExpon, 0, exponent.length);
		Buffer.BlockCopy(modulus, 0, intModul, 0, modulus.length);

		this.exponent = intExpon;
		this.modulus = intModul;
		this.randomize = randomize;
	}

	public Signer(int[] exponent, int[] modulus, boolean randomize) {
		this.exponent = exponent;
		this.modulus = modulus;
		this.randomize = randomize;
	}

	// for compatibility
	public Signer(int[] exponent, int[] modulus) {
		this(exponent, modulus, false);
	}


	public final String sign(String value) {
		byte[] bytes;
		try {
			bytes = value.getBytes("windows-1251");
		} catch (UnsupportedEncodingException e) {
			throw new Error(e.getMessage());
		}

		int[] intSign = sign(bytes);
		byte[] sign = Buffer.GetBytes(intSign);

		StringBuilder sbuf = new StringBuilder(132);
		int pos = 0;
		for (; pos < 66; pos += 2) {
			sbuf.append(String.format("%02x", sign[pos + 1] & 0xFF));
			sbuf.append(String.format("%02x", sign[pos] & 0xFF));
		}
		/*
		 * while (pos++ < 66) { sbuf.append("00"); }
		 */
		return sbuf.toString();
	}


	public final int[] sign(byte[] value) {
		if (value == null) {
			return null;
		}

		int[] signHash = MD4.getInt32Hash(value);

		byte[] rndBuffer = new byte[VALUE_BYTES - HASH_LEN];
		if (randomize) {
			rnd.nextBytes(rndBuffer);
		}

		int[] hashExtended = new int[VALUE_BYTES / INT_BYTES];
		Buffer.BlockCopy(new byte[] { VALUE_BYTES, 0 }, 0, hashExtended, 0, USHORT_BYTES);
		Buffer.BlockCopy(signHash, 0, hashExtended, USHORT_BYTES, HASH_LEN);
		Buffer.BlockCopy(rndBuffer, 0, hashExtended, USHORT_BYTES + HASH_LEN, VALUE_BYTES - USHORT_BYTES - HASH_LEN);

		int[] result = Montgomery.montgomeryExponentiation(hashExtended, exponent, modulus);
		return result;
	}
}